package org.kingdom.utils.qrcode;


import cn.hutool.extra.qrcode.BufferedImageLuminanceSource;
import com.google.zxing.*;
import com.google.zxing.Result;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.Hashtable;

/**
 * 二维码生成
 */
public class QrCode {


    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // 二维码尺寸
    private static final int QRCODE_SIZE_WIDTH = 300;

    private static final int QRCODE_SIZE_HEIGHT = 350;
    // LOGO宽度
    private static final int WIDTH = 60;
    // LOGO高度
    private static final int HEIGHT = 60;

    /**
     * 图片高度增加60
     */
//    private static final int PIC_HEIGHT=HEIGHT+20;
    private static BufferedImage createImage(String content, String imgPath, boolean needCompress, String pressText) throws Exception {
        Hashtable hints = new Hashtable();
        /*hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);*/

        //设置UTF-8， 防止中文乱码
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        //设置二维码四周白色区域的大小
        hints.put(EncodeHintType.MARGIN, 1);
        //设置二维码的容错性
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE_WIDTH, QRCODE_SIZE_HEIGHT, hints);

        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (imgPath == null || "".equals(imgPath)) {
            return image;
        }
        // 插入图片
        insertImage(image, imgPath, needCompress, pressText);
        return image;
    }

    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress, String pressText) throws Exception {
        File file = new File(imgPath);
        if (file.exists()) {
            Image src = ImageIO.read(new File(imgPath));
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            if (needCompress) { // 压缩LOGO
                if (width > WIDTH) {
                    width = WIDTH;
                }
                if (height > HEIGHT) {
                    height = HEIGHT;
                }

                Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
                BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics g = tag.getGraphics();
                g.drawImage(image, 0, 0, null); // 绘制缩小后的图
                g.dispose();
                src = image;
            }
            // 插入LOGO
            Graphics2D graph = source.createGraphics();
            int x = (QRCODE_SIZE_WIDTH - width) / 2;
            int y = (QRCODE_SIZE_HEIGHT - height) / 2;
            graph.drawImage(src, x, y, width, height, null);
            Shape shape = new RoundRectangle2D.Float(x, y, width, height, 6, 6);
            graph.setStroke(new BasicStroke(3f));
            graph.draw(shape);
            graph.dispose();
        }

        if (pressText != null) {
            //计算文字开始的位置
            //x开始的位置：（图片宽度-字体大小*字的个数）/2
            int startX = ((QRCODE_SIZE_WIDTH - (12 * pressText.length())) / 2 - 10) > 0
                    ? ((QRCODE_SIZE_WIDTH - (12 * pressText.length())) / 2 - 10) : 10;
            //y开始的位置：图片高度-（图片高度-图片宽度）/2
            int startY = QRCODE_SIZE_HEIGHT - (QRCODE_SIZE_HEIGHT - QRCODE_SIZE_WIDTH) / 2 + 10;
            try {
                Graphics2D g = source.createGraphics();
//                g.drawImage(source, 0, 0, width, height, null);
                g.setColor(Color.BLUE);
                g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
                g.setFont(new Font("微软雅黑", Font.BOLD, 12));
                g.drawString(pressText, startX, startY);
                g.dispose();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(e);
            }
        }


    }

    /**
     *
     * @param content 二维码内容
     * @param imgPath 图片地址
     * @param destPath 图片地址，创建目录
     * @param needCompress 是否压缩图片
     * @param pressText 二维码名字
     */
    public static void encode(String content, String imgPath, String destPath, boolean needCompress, String pressText) throws Exception {
        BufferedImage image = createImage(content, imgPath, needCompress, pressText);
        mkdirs(destPath);
        ImageIO.write(image, FORMAT_NAME, new File(destPath));
    }

    public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = createImage(content, imgPath, needCompress, null);
        mkdirs(destPath);
        ImageIO.write(image, FORMAT_NAME, new File(destPath));
    }

    public static BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception {
        BufferedImage image = createImage(content, imgPath, needCompress, null);
        return image;
    }

    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        // 当文件夹不存在时，mkdirs会自动创建多层目录，区别于mkdir．(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    public static void encode(String content, String imgPath, String destPath) throws Exception {
        encode(content, imgPath, destPath, false);
    }

    // 被注释的方法
    /*public static void encode(String content, String destPath, boolean
            needCompress) throws Exception {
        QRCodeUtil.encode(content, null, destPath,
                needCompress);
    }*/

    public static void encode(String content, String destPath) throws Exception {
        encode(content, null, destPath, false);
    }

    public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
            throws Exception {
        BufferedImage image = createImage(content, imgPath, needCompress, null);
        ImageIO.write(image, FORMAT_NAME, output);
    }

    public static void encode(String content, OutputStream output) throws Exception {
        encode(content, null, output, false);
    }

    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable hints = new Hashtable();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    public static String decode(String path) throws Exception {
        return decode(new File(path));
    }

    /**
     * 二维码生成
     */
    public static void main(String[] args) {
        try {
            //二维码内容
            String text = "ceshishujufs手动阀手动阀";
            //二维码的图片路径
            String imgPath = "H:\\photo" + File.separator;

            //二维码名称
            String fileName = "test0.0.jpg";

            String qrcodePath = imgPath + fileName;
            //生成二维码
            encode(text, qrcodePath, qrcodePath, false,"二维码名称");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.4.0</version>
	</dependency>
    */
}
